package underweight

import (
	"adam2/internal/constants"
	"adam2/internal/model"
	"adam2/internal/properties"
	"adam2/internal/util"
	"anubis-framework/pkg/io"
	"fmt"
	"gorm.io/gorm"
)

// 根据牛熊线减仓
type BullShortLineUnderweight struct {
	db *gorm.DB
}

// 初始化
func (b *BullShortLineUnderweight) Init(db *gorm.DB) {
	b.db = db
}

// 执行，返回值为true表示已经减仓，否则为false
func (b *BullShortLineUnderweight) Exec(transactionDate string) {
	io.Infoln("根据牛熊线减仓，日期[%s]", transactionDate)

	// 是否减仓了
	//var underweight bool = false

	var quantAccountLogArray *model.QuantAccountLogArray = &model.QuantAccountLogArray{}
	b.db.Raw("select * from quant_account_log t where t.date_=to_date(?, 'yyyy-mm-dd')", transactionDate).Scan(quantAccountLogArray)

	if nil != quantAccountLogArray && len(*quantAccountLogArray) > 0 {
		for _, quantAccountLog := range *quantAccountLogArray {
			// 如果对应账号的仓位已经空仓，则不用再减仓
			var optimizeAccount *model.OptimizeAccount = &model.OptimizeAccount{}
			b.db.Raw("select * from optimize_account t where t.account_name=?", quantAccountLog.AccountName).Scan(optimizeAccount)
			if optimizeAccount.HoldStockNumber == 0 {
				continue
			}

			// 表示牛熊线
			var bullShortLine float64
			// 是否在牛熊线之下
			var belowBullShortLine bool = false
			if !belowBullShortLine && quantAccountLog.Bias250 != 0 && quantAccountLog.Bias250 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias250 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma250
				if quantAccountLog.TotalAssets < bullShortLine {
					belowBullShortLine = true
				}
			}
			if !belowBullShortLine && quantAccountLog.Bias120 != 0 && quantAccountLog.Bias120 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias120 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma120
				if quantAccountLog.TotalAssets < bullShortLine {
					belowBullShortLine = true
				}
			}
			if !belowBullShortLine && quantAccountLog.Bias60 != 0 && quantAccountLog.Bias60 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias60 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma60
				if quantAccountLog.TotalAssets < bullShortLine {
					belowBullShortLine = true
				}
			}
			if !belowBullShortLine && quantAccountLog.Bias20 != 0 && quantAccountLog.Bias20 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias20 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma20
				if quantAccountLog.TotalAssets < bullShortLine {
					belowBullShortLine = true
				}
			}
			if !belowBullShortLine && quantAccountLog.Bias10 != 0 && quantAccountLog.Bias10 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias10 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma10
				if quantAccountLog.TotalAssets < bullShortLine {
					belowBullShortLine = true
				}
			}
			if !belowBullShortLine && quantAccountLog.Bias5 != 0 && quantAccountLog.Bias5 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias5 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma5
				if quantAccountLog.TotalAssets < bullShortLine {
					belowBullShortLine = true
				}
			}
			// 如果最后任何bias指标都无法确定哪一根均线可以作为牛熊线的话，则将前一个交易日的总资产作为牛熊线
			b.db.Raw("select t1.total_assets from (select * from quant_account_log t where t.account_name=? and t.date_<to_date(?, 'yyyy-mm-dd') order by t.date_ desc) t1 "+
				"where rownum<=1", quantAccountLog.AccountName, transactionDate).Scan(&bullShortLine)
			if quantAccountLog.TotalAssets < bullShortLine {
				belowBullShortLine = true
			}

			// 减仓
			if belowBullShortLine {
				//underweight = true
				var overOrUnderWeightAmount int = properties.QuantProperties_.OverOrUnderWeightAmount
				// 查询可以减仓的股票
				var optimizeStockTransactRecordArray *model.OptimizeStockTransactRecordArray = &model.OptimizeStockTransactRecordArray{}
				b.db.Raw("select t.* from optimize_stock_transact_record t "+
					"join stock_transaction_data_all stda on stda.code_=t.stock_code and stda.date_=to_date(?, 'yyyy-mm-dd') "+
					"where t.account_name=? and t.sell_date is null and t.sell_price is null and t.sell_amount is null "+
					"order by stda.total_market_value desc", transactionDate, optimizeAccount.AccountName).Scan(optimizeStockTransactRecordArray)
					//"order by stda.circulation_market_value desc", transactionDate, optimizeAccount.AccountName).Scan(optimizeStockTransactRecordArray)
				if nil != optimizeStockTransactRecordArray && len(*optimizeStockTransactRecordArray) > 0 {
					for _, optimizeStockTransactRecord := range *optimizeStockTransactRecordArray {
						if overOrUnderWeightAmount > 0 {
							var stockTransactionDataAll model.StockTransactionDataAll
							b.db.Raw("select * from stock_transaction_data_all t where t.code_=? and t.date_=to_date(?,'yyyy-mm-dd')", optimizeStockTransactRecord.StockCode, transactionDate).Scan(&stockTransactionDataAll)

							// 如果没有查找到记录，可能是因为这个股票在这个交易日停牌，因此跳过这条记录
							if stockTransactionDataAll.ID == 0 {
								b.db.Exec("update optimize_stock_transact_record t set t.fail_sell_reason=? where t.id_=?", constants.SUSPENSION, optimizeStockTransactRecord.ID)
								io.Infoln("股票[%s]在日期[%s]没有查找到记录，可能是因为这个股票在这个交易日停牌，因此跳过这条记录", optimizeStockTransactRecord.StockCode, transactionDate)
								continue
							}

							// 如果是一字跌停板，因此跳过这条记录
							if util.OneWordLimitDown(stockTransactionDataAll, transactionDate) {
								b.db.Exec("update optimize_stock_transact_record t set t.fail_sell_reason=? where t.id_=?", constants.LIMIT_DOWN, optimizeStockTransactRecord.ID)
								io.Infoln("股票[%s]在日期[%s]是一字跌停板，因此跳过这条记录", optimizeStockTransactRecord.StockCode, transactionDate)
								continue
							}

							b.db.Exec("update optimize_stock_transact_record ostr "+
								"set ostr.sell_date=to_date(?, 'yyyy-mm-dd'), ostr.sell_price=?, ostr.sell_amount=?, "+
								"ostr.profit_and_loss=round(?, 4), ostr.profit_and_loss_rate=?, "+
								"ostr.stamp_duty = ROUND(ostr.buy_amount * "+fmt.Sprintf("%f", stockTransactionDataAll.ClosePrice)+" * "+fmt.Sprintf("%f", properties.QuantProperties_.StampDutyRate)+", 4), "+
								"ostr.registration_fee_when_sell = ?, "+
								"ostr.commission_when_sell = ? "+
								"where ostr.account_name=? and ostr.stock_code=? and ostr.buy_date=?",
								transactionDate, stockTransactionDataAll.ClosePrice, optimizeStockTransactRecord.BuyAmount,
								(stockTransactionDataAll.ClosePrice-optimizeStockTransactRecord.BuyPrice)*float64(optimizeStockTransactRecord.BuyAmount), (stockTransactionDataAll.ClosePrice-optimizeStockTransactRecord.BuyPrice)/optimizeStockTransactRecord.BuyPrice*100,
								util.CalculateRegistrationFee(optimizeStockTransactRecord.StockCode, optimizeStockTransactRecord.BuyAmount),
								util.CalculateCommission(stockTransactionDataAll.ClosePrice, optimizeStockTransactRecord.BuyAmount),
								optimizeStockTransactRecord.AccountName, optimizeStockTransactRecord.StockCode, optimizeStockTransactRecord.BuyDate)
							overOrUnderWeightAmount--
						} else {
							break
						}
					}
				}
			}
		}
	}
	//return underweight
}
